//
// Created by Martin on 2022/10/1.
//

#include <boost/static_assert.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/vector_c.hpp>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace boost;

// 数值wrapper
// T: 数值类型, D: T的量纲
template<class T, class D>
struct quantity
{
    explicit quantity(T x)
    : m_value(x)
    {}

    // 转换构造器
    template<class OtherDimensions>
    quantity(quantity<T, OtherDimensions> const& rhs)
    : m_value(rhs.value())
    {
        BOOST_STATIC_ASSERT((
                mpl::equal<D, OtherDimensions>::type::value
        ));
    }

    T value() const { return m_value; }

private:
    T m_value;
};

template<class T, class D>
quantity<T, D>
operator+(quantity<T, D> x, quantity<T, D> y)
{
    return quantity<T, D>(x.value() + y.value());
}

template<class T, class D1, class D2>
quantity<T, D1> operator+(quantity<T, D1> x, quantity<T, D2> y)
{
    return x + static_cast<quantity<T, D1>>(y);
    // same with the following return expression:
    // return operator+(x, quantity<T, D1>(y));
}

template<class T, class D>
quantity<T, D>
operator-(quantity<T, D> x, quantity<T, D> y)
{
    return quantity<T, D>(x.value() - y.value());
}

// 加法元函数类
struct plus_f0
{
    template<class T1, class T2>
    struct apply
    {
        typedef typename mpl::plus<T1, T2>::type type;
    };
};

// 使用元函数转发, 改进元函数apply
struct plus_f
{
    template<class T1, class T2>
    struct apply : mpl::plus<T1, T2>
    {
    };
};

template<class T, class D1, class D2>
quantity<
        T,
        // transform第三个模板参数BinaryOperation需要一个类型, 而不是一个类模板.
        // 因此, 不能直接将类模板传给transform
        // 新量纲
        typename mpl::transform<D1, D2, plus_f>::type
>
operator*(quantity<T, D1> x, quantity<T, D2> y)
{
    typedef typename mpl::transform<D1, D2, plus_f>::type dim;
    return quantity<T, dim>(x.value() * y.value());
}

// 减法元函数类
struct minus_f0
{
    template<class T1, class T2>
    struct apply
    {
        typedef typename mpl::minus<T1, T2>::type type;
    };
};

// 使用元函数转发, 改进元函数apply
struct minus_f
{
    template<class T1, class T2>
    struct apply : mpl::minus<T1, T2>{};
};

template<class T, class D1, class D2>
quantity<
        T,
        typename mpl::transform<D1, D2, minus_f>::type
>
operator/(quantity<T, D1> x, quantity<T, D2> y)
{
    typedef typename mpl::transform<D1, D2, minus_f>::type dim;
    return quantity<T, dim>(x.value() / y.value());
}

// 基本量纲
typedef mpl::vector_c<int, 1, 0, 0, 0, 0, 0, 0> mass;
typedef mpl::vector_c<int, 0, 1, 0, 0, 0, 0, 0> length;
typedef mpl::vector_c<int, 0, 0, 1, 0, 0, 0, 0> time0;
typedef mpl::vector_c<int, 0, 0, 0, 1, 0, 0, 0> charge;
typedef mpl::vector_c<int, 0, 0, 0, 0, 1, 0, 0> temperature;
typedef mpl::vector_c<int, 0, 0, 0, 0, 0, 1, 0> intensity;
typedef mpl::vector_c<int, 0, 0, 0, 0, 0, 0, 1> amount_of_substance;

// 复合量纲
typedef mpl::vector_c<int, 0, 1, -1, 0, 0, 0, 0> velocity;       // l/t
typedef mpl::vector_c<int, 0, 1, -2, 0, 0, 0, 0> acceleration;   // l/(t^2)
typedef mpl::vector_c<int, 1, 1, -1, 0, 0, 0, 0> momentum;       // ml/t
typedef mpl::vector_c<int, 1, 1, -2, 0, 0, 0, 0> force;          // ml/(t^2)


int main()
{
    BOOST_STATIC_ASSERT((
            mpl::plus<mpl::int_<2>,
                    mpl::int_<3>
            >::type::value == 5
    ));

    quantity<float, mass> m(5.0f);
    quantity<float, acceleration> a(9.8f);
//    quantity<float, force> f0 = m * a;
//    quantity<float, force> f1 = f1 + f0;

    quantity<float, force> f = f + static_cast<quantity<float, force>>(m * a);

    cout << "force = " << (m * a).value() << endl;
    cout << "force = " << f.value() << endl;

    cout << "valid ok" << endl;
    return 0;
}
